﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace MagickConverter
{
    public class MagickTask
    {
        private const string EXE = "magick";
        private const string Format = "convert -verbose -density {0} -quality {1} -resize {2} -background white -alpha remove {3} {4}";
        private string WorkDir { get; }
        private string Arguments { get; }

        public string Id { get; set; }

        public bool IsFinished { get; private set; } = false;

        public event Action NextTaskEvent;

        public event Action<string> BuidingEvent;

        public event Action<Queue<string>> FinishedEvent;

        private DateTime StartTime { get; }

        public TimeSpan Duration => DateTime.Now - StartTime;

        public string Source { get; }

        private string Dir { get; }

        public Queue<string> Files { get; }

        public MagickTask(string root, int density, int quality, string size)
        {
            Id = Guid.NewGuid().ToString("N");
            StartTime = DateTime.Now;
            WorkDir = new FileInfo(Assembly.GetEntryAssembly().Location).Directory.FullName;
            Dir = Path.Combine(root, Id);
            Source = Path.Combine(root, Id, "0.pdf");
            var dest = Path.Combine(root, Id, "%d.jpg");
            Arguments = string.Format(Format, density, quality, size, Source, dest);
            Files = new Queue<string>();
        }

        public void Convert()
        {
            if (IsFinished)
                throw new Exception("Cannot start task when it's finished");
            try
            {
                Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
        }

        private void Start()
        {
            if (!Directory.Exists(Dir)) Directory.CreateDirectory(Dir);
            BuidingEvent(Source);
            var startInfo = new ProcessStartInfo
            {
                FileName = EXE,
                Arguments = Arguments,
                WorkingDirectory = WorkDir,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            };
            using var process = new Process();
            process.StartInfo = startInfo;
            process.ErrorDataReceived += new DataReceivedEventHandler(OnErrorDataReceived);
            process.OutputDataReceived += new DataReceivedEventHandler(OnOutputDataReceived);
            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();
            process.WaitForExit();
            IsFinished = true;
            File.Delete(Source);//删除资源文件
            FinishedEvent(Files);
            if (Directory.Exists(Dir)) Directory.Delete(Dir, true);
            NextTaskEvent();
        }

        private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            ParseLine(e.Data);
        }

        private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            ParseLine(e.Data);
        }

        private void ParseLine(string line)
        {
            if (string.IsNullOrEmpty(line)) return;
            if (!line.Contains("=>")) return;
            AddFile();
        }

        private void AddFile()
        {
            var length = Files.Count;
            var file = Path.Combine(Dir, $"{length}.jpg");
            Files.Enqueue(file);
        }
    }
}
